<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>end与addBack</title>
</head>
<body>
    <!-- dom -->
    <button id="end">点击end处理</button>
    <button id="addBack">点击addBack处理</button>

    <ul class="first">
        <li class="foo"><span>list item 1</span></li>
        <li>list item 2</li>
        <li class="bar">list item 3</li>
    </ul>
    <ul class="second">
        <li class="foo">list item 1</li>
        <li>list item 2</li>
        <li class="bar">list item 3</li>
    </ul>

    <!-- js -->
    <script src="../assets/libs/jquery-2.0.3.js"></script>
    <script>
        /**
         * end方法就是回溯到上一个Dom合集,因此对于链式操作与优化，这个方法还是很有意义的
         * .end()jQuery对象维护一个堆栈内部来跟踪匹配的元素集合的变化。
         * 当一个DOM遍历方法被调用时，新的元素集合推入到堆栈中。 
         * 如果还需要包含先前的元素集合，.addBack()
         */ 

        // .end() 返回当前栈的上一个元素合集
        $("#end").click(function(){
            $('ul.first').find('.foo').css('background-color', 'red').end().find('.bar').css('background-color', 'green');  
            $('ul.first').find('.foo').css('background-color', 'red').find('span').end().find('.bar').css('background-color', 'green');  
            console.log('$("ul.first").end() :>> ', $("ul.first").end());  // document
            console.log('$("ul.first").find(".foo") :>> ', $("ul.first").find(".foo")); // jqueryDom: .foo
            console.log('$("ul.first").find(".foo").end() :>> ', $("ul.first").find(".foo").end()); //jqueryDom: ul.first
            console.log('$("ul.first").find(".foo").find(“span”).end() :>> ', $("ul.first").find(".foo").find('span').end());//jqueryDom: .foo

            console.log('$("ul.first").find(".foo").addBack() :>> ', $("ul.first").find(".foo").addBack()); // jqueryDom(length:2): 1-ul.first  2-.foo
        })

        // addBack包含了自身的选择器, 返回之前栈中所有的jQuery元素
        $("#addBack").click(function(){
            $('.foo').nextAll().addBack().css('background-color', 'red');
            console.log('$(".foo") :>> ', $('.foo'));
            console.log('$(".foo").nextAll() :>> ', $('.foo').nextAll());
            console.log('$(".foo").nextAll().addBack() :>> ', $('.foo').nextAll().addBack());
        })
    </script>

    <script>
        // 源码
        pushStack: function (elems) {

            // Build a new jQuery matched element set
            // this.constructor = jQuery = function() { return new jQuery.fn.init() }
            // ret 就是构建出来的新jQuery对象，this就是当前的jQuery对象
            var ret = jQuery.merge( this.constructor(), elems );

            // 将当前的jQuery对象挂载到新构建的jQuery对象上，通过prevObject来引用
            // Add the old object onto the stack (as a reference)
            ret.prevObject = this;
            ret.context = this.context;

            // Return the newly-formed element set
            return ret;
        },

        jQuery.fn.extend({
            find: function( selector ) {
                var i,
                    ret = [],
                    self = this,
                    len = self.length;

                if ( typeof selector !== "string" ) {
                    return this.pushStack( jQuery( selector ).filter(function() {
                        for ( i = 0; i < len; i++ ) {
                            if ( jQuery.contains( self[ i ], this ) ) {
                                return true;
                            }
                        }
                    }) );
                }

                for ( i = 0; i < len; i++ ) {
                    // 通过sizzle选择器，返回结果集
                    jQuery.find( selector, self[ i ], ret );
                }

                // 通过jQuery.find后得到结果ret这个就是纯的DOM节点
                // Needed because $( selector, context ) becomes $( context ).find( selector )
                ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
                ret.selector = this.selector ? this.selector + " " + selector : selector;
                return ret;
            },
        })
    </script>
</body>
</html>